{
  LW Monitor -- LightWave Progress Monitor

  Monitors are simple data structures defining an interface which the
  server can use to give feedback to the host on its progress in
  performing some task.  They are sometimes passed servers to give
  feedback on the progress of the particular operation, and can sometimes
  be accessed from within a server that wants to show its progress on a
  slow operation using the host's normal feedback display.

  Based on lwmonitor.h which is:
  Copyright 1999, NewTek, Inc.
}

{
  Copyright 2012, Jameel Halabi

  This unit is part of the BlaiseWave wrapper,
  which is licensed under the BSD 2-Clause license (see licenses/license.txt).
}


unit LW_Monitor;

{$mode objfpc}{$H+}

interface

const
  LWMONITOR_GLOBAL   = 'LWM: Dynamic Monitor';
  LWLMONFUNCS_GLOBAL = 'LWLMonFuncs';

  {
    UI Option Flags
    NOABORT:
     Abort button is disabled. Default is operation can be aborted.
    REVIEW:
     Monitor remains open after 'done' method is called. This allows user
     to review messages. Default is no review and mediately from done method
    HISTAPPEND:
     History file is appended with new messages. Default is overwrite.
    IMMUPD:
     Enables immediate update of the monitor on every step. The default
     is to delay updates to avoid incurring too much overhead for rapid
     step events.
    TOOLBAR:
     Uses the Layout tooltip bar to display the progress. No monitor window
     will be opened. If abort handling is enabled, pressing the default abort
     key (Esc) will trigger an abort return from the step function.
  }
  LMO_NOABORT    = 1 shl 0;
  LMO_REVIEW     = 1 shl 1;
  LMO_HISTAPPEND = 1 shl 2;
  LMO_IMMUPD     = 1 shl 3;
  LMO_TOOLBAR    = 1 shl 4;

type
  {
    An LWMonitor struct consists of some generic data and three functions:
    init, step and done.  The 'init' function is called first with the
    number of steps in the process to be monitored, which is computed by
    the server.  As the task is processed, the 'step' function is called
    with the number of steps just completed (often one).  These step
    increments should eventually add up to the total number and then the
    'done' function is called, but 'done' may be called early if there was
    a problem or the process was aborted.  The 'step' function will return
    one if the user requested an abort and zero otherwise.

    The server is masked from any errors in the monitor that may occur on
    the host side of the interface.  If there is a problem with putting up
    a monitor, the functions will still return normally, since the monitor
    is for user feedback and is not that critical.
  }
  PLWMonitor = ^LWMonitor;
  LWMonitor  = record
    Data : Pointer;

    Init : procedure (Data : Pointer; StepsCount : UInt32) ;
    Step : function  (Data : Pointer; StepsDone  : UInt32) : Integer;
    Done : procedure (Data : Pointer)                      ;
  end;

  {
    Create:
    Creates a new monitor instance

    Setup:
    Configures the progress monitor
      Title    - Monitor Title
      UIFlags  - a bitmask of desired LMO_* flags
      HistFile - if given, filename where messages will also be written
      UIflags  - takes a bitmask of ui options

    SetWinPos:
      XYWH     - position and size of monitor window

    Init:
    Sets total number of steps and OOpens the monitor progress window
      Total    - Total number of steps
      Msg      - Initial message string for user

    Step:
    Increments the current step and sets the display message
      Incr     - Increment to increase counter (0 is valid)
      Msg      - Message string for user

    Done:
    Indicates the processing is complete. If review option enabled,
    monitor remains open in a modal state for user review of output.
    Control will not return to caller until the user dismisses the window.

    Destroy:
    Closes the window (if open) and destroys the instance.
  }
  PLWLMon = ^LWLMon;
  LWLMon  = record end;

  PLWLMonFuncs = ^LWLMonFuncs;
  LWLMonFuncs  = record
    Create    : function                               : PLWLMon;
    Setup     : procedure (      Mon        : PLWLMon;
                                 Title      : PChar  ;
                                 UIFlags    : UInt32 ;
                           const HistFile   : PChar  ) ;
    SetWinPos : procedure (      Mon        : PLWLMon;
                                 X, Y, W, H : Integer) ;
    Init      : procedure (      Mon        : PLWLMon;
                                 Total      : UInt32 ;
                           const Msg        : PChar  ) ;
    Step      : function  (      Mon        : PLWLMon;
                                 Incr       : UInt32 ;
                           const Msg        : PChar  ) : Integer;
    Done      : procedure (      Mon        : PLWLMon) ;
    Destroy   : procedure (      Mon        : PLWLMon) ;
  end;

{
  Macros are provided to call a monitor which will do nothing if the
  monitor pointer is null.  MON_INCR is used for step sizes greater than
  one and MON_STEP is used for step sizes exactly one.
}
procedure MON_INIT(Mon : PLWMonitor; Count : UInt32) ;
function  MON_INCR(Mon : PLWMonitor; D     : UInt32) : Integer;
function  MON_STEP(Mon : PLWMonitor                ) : Integer;
procedure MON_DONE(Mon : PLWMonitor                ) ;

{
  Macros to simplify some common operations.
}
// Creates a monitor instance
function  LMON_NEW (      Fun        : PLWLMonFuncs) : PLWLMon;

// Initailizes a default monitor
procedure LMON_DFLT(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          Tot        : UInt32      ) ;


procedure LMON_WPOS(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          X, Y, W, H : Integer     ) ;

procedure LMON_INIT(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          Tot        : UInt32      ) ;

// The following are various incrementing macros
function  LMON_STEP(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) : Integer;

function  LMON_INCR(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          S          : UInt32      ) : Integer;

function  LMON_MSG (      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                    const Msg        : PChar       ) : Integer;

function  LMON_MSGS(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                    const Msg        : PChar       ) : Integer;

function  LMON_MSGI(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          S          : UInt32      ;
                    const Msg        : PChar       ) : Integer;

// These finish and destroy the monitor
procedure LMON_DONE(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) ;

procedure LMON_KILL(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) ;

implementation

procedure MON_INIT(Mon : PLWMonitor; Count : UInt32) ;          inline;
begin
  if Assigned(Mon) then
    Mon^.Init(Mon^.Data, Count);
end;
function  MON_INCR(Mon : PLWMonitor; D     : UInt32) : Integer; inline;
begin
  if Assigned(Mon) then
    Mon^.Step(Mon^.Data, D)
  else
    Result := 0;
end;
function  MON_STEP(Mon : PLWMonitor                ) : Integer; inline;
begin
  Result := MON_INCR(Mon, 1);
end;
procedure MON_DONE(Mon : PLWMonitor                ) ;          inline;
begin
  if Assigned(Mon) then
    Mon^.Done(Mon^.Data);
end;

function  LMON_NEW (      Fun        : PLWLMonFuncs) : PLWLMon; inline;
begin
  Result := Fun^.Create();
end;

procedure LMON_DFLT(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          Tot        : UInt32      ) ;          inline;
begin
  Fun^.Setup(Mon, 'Processing...', 0, nil);
  Fun^.Init (Mon, Tot, nil);
end;

procedure LMON_WPOS(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          X, Y, W, H : Integer     ) ;          inline;
begin
  Fun^.SetWinPos(Mon, X, Y, W, H);
end;
procedure LMON_INIT(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          Tot        : UInt32      ) ;          inline;
begin
  Fun^.Init(Mon, Tot, nil);
end;
function  LMON_STEP(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) : Integer; inline;
begin
  Result := Fun^.Step(Mon, 1, nil);
end;
function  LMON_INCR(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          S          : UInt32      ) : Integer; inline;
begin
  Result := Fun^.Step(Mon, S, nil);
end;
function  LMON_MSG (      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                    const Msg        : PChar       ) : Integer; inline;
begin
  Result := Fun^.Step(Mon, 0, Msg);
end;
function  LMON_MSGS(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                    const Msg        : PChar       ) : Integer; inline;
begin
  Result := Fun^.Step(Mon, 1, Msg);
end;
function  LMON_MSGI(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ;
                          S          : UInt32      ;
                    const Msg        : PChar       ) : Integer; inline;
begin
  Result := Fun^.Step(Mon, S, Msg);
end;

procedure LMON_DONE(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) ;          inline;
begin
  Fun^.Done(Mon);
end;
procedure LMON_KILL(      Fun        : PLWLMonFuncs;
                          Mon        : PLWLMon     ) ;          inline;
begin
  Fun^.Destroy(Mon);
end;

end.

